#ifndef PROB_GUESS_H
#define PROB_GUESS_H


#include <bitset>
#include "packet.h"
#include "packet-info.h"
#include "mobilenode.h"
#include "virqueue.h"
#include "uthash.h"
#include <iostream>
#include <map>

#define ALPHA        0.3 //modified later, weighting factor
#define T            0.1 // time period, same with fixed state report peroid     
#define CUR_TIME    Scheduler::instance().clock()


using std::bitset;
using std::map;
/** this is the key of the hash table
 */
struct prob_key_t{
    int nodeid;
    int src_ip;
    inline bool operator < (const prob_key_t rhs) const {
        
	if( nodeid < rhs.nodeid )
	  return true;
	else if ( nodeid > rhs.nodeid )
	  return false;
	else {
	  if( src_ip < rhs.src_ip )
	    return true;
	}
	
	return false;	
    }
};

/** the real hash table entry
 */
/* typedef struct { */
/*     prob_key_t key; */
/*     uint8_t prob; */
    
/*     UT_hash_handle hh; */
/* } prob_info_t; */

/** info for each source ip
 */
typedef struct {
    nsaddr_t src_ip;
    uint16_t start_seq_num;
    uint16_t end_seq_num;
    int pkt_count;
} src_info_t;

/** info for each neighbor
 */
typedef struct {
    int nodeid;
    double last_report_time;
} nb_info_t;

class COPENeighbor;
struct nb_head;

typedef list<nb_info_t>::iterator NB_INFO_ITER ;
typedef list<src_info_t>::iterator SRC_INFO_ITER ;
typedef map< prob_key_t, double> prob_info_t;
typedef map< prob_key_t, double>::iterator PROB_INFO_ITER;

class ProbGuess {
 public:
    ProbGuess(MobileNode *);

    ~ProbGuess();
    
   
    /* 
     * update prob_info_table_ when packet-info updated,
     * which means a state report received 
     */
    void  up_prob_info(int /* nb_id */,  
		       nb_head * /* neighbor list */, 
		       VirQueue * /* virtual queue */,
		       PacketInfo * /* pkt_info */);
  
    //if prob not exist, return 0
    double get_prob_guess(int /* src ip */, int /* neighbor id */);

 
 private:
    
    prob_info_t prob_info_table_; //index by key
    list<src_info_t> * src_info_list_; // indexed by src_ip
    //list<nb_info_t*> * nb_info_list_; // index by nodeid
    list<nb_info_t> * nb_info_list_;
    
    nb_info_t * get_nb_info(int /* nb_id */);
    /*
     * An assistant function for up_prob_info, will update src_info_list 
     * according to a virtual queue
     */
    void up_src_list(VirQueue * /* virtual queue */, int, char);
    /*
     * An assistant function for up_src_info
     */
    void up_src_item(nsaddr_t /* src_ip */, 
		     u_int16_t /* seq_num */);
    /*
     * An assistant function for up_prob_info, will update new prob for an
     * item in prob table, indexed by key 
     */
    void up_prob_info_item(prob_key_t /* key */, double /* new_prob */);
    
    /* reset src list each time after updating prob_info_table_ */
    void reset_src_list();

    /* find a specific prob_info_t item */
    prob_info_t* find_prob_guess(int src_ip, int nb_id);
};

#endif
